package com.group4.datafactorybackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.group4.datafactorybackend.common.DataFactoryConstantPool;
import com.group4.datafactorybackend.common.R;
import com.group4.datafactorybackend.common.enums.MyEnumClass;
import com.group4.datafactorybackend.common.enums.ResultCodeEnum;
import com.group4.datafactorybackend.common.exception.DataFactoryException;
import com.group4.datafactorybackend.entity.DO.ApcStopwatchDO;
import com.group4.datafactorybackend.entity.DO.DcStopwatchDO;
import com.group4.datafactorybackend.entity.DO.EncodingConfigurationDO;
import com.group4.datafactorybackend.entity.DO.StopwatchDO;
import com.group4.datafactorybackend.entity.DTO.BatchReleaseOrOutageDTO;
import com.group4.datafactorybackend.entity.DTO.CreateOrUpdateStopwatchDTO;
import com.group4.datafactorybackend.entity.DTO.StopwatchConfigDTO;
import com.group4.datafactorybackend.entity.DTO.StopwatchParameterDTO;
import com.group4.datafactorybackend.entity.VO.EncodingConfigurationExcelVO;
import com.group4.datafactorybackend.entity.VO.StopWatchExcelVO;
import com.group4.datafactorybackend.entity.VO.StopwatchDetailVO;
import com.group4.datafactorybackend.mapper.ApcStopwatchMapper;
import com.group4.datafactorybackend.mapper.DcStopwatchMapper;
import com.group4.datafactorybackend.mapper.EncodingConfigurationMapper;
import com.group4.datafactorybackend.mapper.StopwatchManagementMapper;
import com.group4.datafactorybackend.service.StopwatchManagementService;
import com.group4.datafactorybackend.util.BeanCopyUtil;
import com.group4.datafactorybackend.util.CodeUtil;
import com.group4.datafactorybackend.util.ExcelUtils;
import com.group4.datafactorybackend.util.SizeUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 卑微小峰
 * @date 2022/8/1
 * @description 码表管理业务逻辑实现层
 */
@Service
public class StopwatchManagementServiceImpl extends ServiceImpl<StopwatchManagementMapper,StopwatchDO> implements StopwatchManagementService {

    @Autowired
    private StopwatchManagementMapper stopwatchManagementMapper;

    @Autowired
    private EncodingConfigurationMapper encodingConfigurationMapper;

    @Autowired
    private ApcStopwatchMapper apcStopwatchMapper;

    @Autowired
    private DcStopwatchMapper dcStopwatchMapper;

    /**
     * @author 卑微小峰
     * @param batchReleaseOrOutageDTO （批量）发布/停用接收参数实体类
     * @return R
     * @description （批量）发布/停用码表
     */
    @Override
    public R<?> releaseOrOutage(BatchReleaseOrOutageDTO batchReleaseOrOutageDTO) {
        Integer status = batchReleaseOrOutageDTO.getStatus();
        List<String> stopwatchCodeList = batchReleaseOrOutageDTO.getCodeList();

        // （批量）停用时判断批量操作中是否存在未发布的码表
        LambdaQueryWrapper<StopwatchDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (status.equals(MyEnumClass.StatusEnum.HAVE_DISABLE.getCode())) {
            lambdaQueryWrapper.eq(StopwatchDO::getStopwatchStatus, MyEnumClass.StatusEnum.NOT_RELEASE.getCode())
                    .in(StopwatchDO::getStopwatchCode, stopwatchCodeList);
            int result = stopwatchManagementMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_NOT_RELEASE.getCode(), "存在未发布的码表");
            }
        }
        // （批量）发布时判断批量操作中是否存在已发布的码表
        if (status.equals(MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())) {
            lambdaQueryWrapper.eq(StopwatchDO::getStopwatchStatus, MyEnumClass.StatusEnum.HAVE_RELEASE.getCode())
                    .in(StopwatchDO::getStopwatchCode, stopwatchCodeList);
            int result = stopwatchManagementMapper.selectCount(lambdaQueryWrapper);
            if (result > 0) {
                return R.Failed(ResultCodeEnum.EXIST_HAVE_RELEASE.getCode(), "存在已发布的码表");
            }
        }

        // 判断是否含有被接口参数配置或数据标准字段引用的码表
        int bool = 0;
        for (String stopwatchCode : stopwatchCodeList) {
            if (bool == 0) {
                // 判断是否被未停用的接口参数配置引用
                LambdaUpdateWrapper<ApcStopwatchDO> isBeAdoptedByApiWrapper = new LambdaUpdateWrapper<>();
                isBeAdoptedByApiWrapper.eq(ApcStopwatchDO::getStopwatchCode,stopwatchCode)
                        .set(ApcStopwatchDO::getIsDisable, MyEnumClass.QuoteStatusEnum.OPEN_QUOTE.getCode());
                bool = apcStopwatchMapper.update(null, isBeAdoptedByApiWrapper);
                if (bool == 0) {
                    // 判断是否被未停用的数据标准引用
                    LambdaUpdateWrapper<DcStopwatchDO> isBeAdoptedByDataCriterionWrapper = new LambdaUpdateWrapper<>();
                    isBeAdoptedByDataCriterionWrapper.eq(DcStopwatchDO::getStopwatchCode,stopwatchCode)
                            .set(DcStopwatchDO::getIsDisable, MyEnumClass.QuoteStatusEnum.OPEN_QUOTE.getCode());
                    bool = dcStopwatchMapper.update(null, isBeAdoptedByDataCriterionWrapper);
                }
            }else {
                return R.Failed(ResultCodeEnum.BEING_CITED.getCode(),"码表：" + stopwatchCode + ResultCodeEnum.BEING_CITED.getMessage());
            }
        }

        // （批量）发布/停用码表
        LambdaUpdateWrapper<StopwatchDO> releaseOrOutageWrapper = new LambdaUpdateWrapper<>();
        releaseOrOutageWrapper.in(StopwatchDO::getStopwatchCode,stopwatchCodeList)
                .set(StopwatchDO::getStopwatchStatus,status);
        int result = stopwatchManagementMapper.update(null,releaseOrOutageWrapper);
        if (result > 0) {
            return R.Success(ResultCodeEnum.OPERATION_SUCCESS,result);
        }
        return R.Failed(ResultCodeEnum.OPERATION_FAILED);

    }

    /**
     * @author 邹代鑫
     * @param createOrUpdateStopwatchDTO 新增、修改码表接收参数实体类
     * @return boolean
     * @description 新增码表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> addStopwatch(CreateOrUpdateStopwatchDTO createOrUpdateStopwatchDTO) {
        /*
        新增码表验证：
         1、判断码表名称不能与数据库重复
         2、判断配置项不能为空
         3、判断新增配置项名称、值不能重复
        */

        // 判断码表名称名是否与数据库重复
        LambdaQueryWrapper<StopwatchDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StopwatchDO::getStopwatchName,createOrUpdateStopwatchDTO.getStopwatchName());
        int count = stopwatchManagementMapper.selectCount(lambdaQueryWrapper);
        if (count > 0){
            // 码表名称重复，抛出传入参数异常
            throw new DataFactoryException(ResultCodeEnum.STOPWATCH_NAME_EXIST.getMessage());
        }

        // 判断码表配置项是否为空
        if (createOrUpdateStopwatchDTO.getConfigList().size() <= 0) {
            return R.Failed(ResultCodeEnum.STOPWATCH_ENCODING_IS_NULL);
        }

        // 判断新增码表配置项的码值取值、码值名称是否为空
        List<StopwatchConfigDTO> configs = createOrUpdateStopwatchDTO.getConfigList();
        List<String> encodingValue = new ArrayList<>();
        List<String> encodingNames = new ArrayList<>();
        for (StopwatchConfigDTO config : configs) {
            encodingValue.add(config.getEncodingValue());
            encodingNames.add(config.getEncodingName());
        }
        // 判断新增码表配置项的码值取值是否存在重复
        boolean bool = SizeUtils.siblingRepetition(encodingValue);
        if (!bool){
            return R.Failed(ResultCodeEnum.ENCODING_CONFIGURATION_VALUE_REPEAT);
        }
        // 判断新增码表配置项的码值名称是否存在重复
        bool = SizeUtils.siblingRepetition(encodingNames);
        if (!bool){
            return R.Failed(ResultCodeEnum.ENCODING_CONFIGURATION_NAME_REPEAT);
        }

        // 存入码表名和码表信息
        StopwatchDO stopwatchDO = new StopwatchDO();
        BeanUtils.copyProperties(createOrUpdateStopwatchDTO,stopwatchDO);
        this.stopwatchManagementMapper.insert(stopwatchDO);
        // 将主键自增回填的数据进行处理
        String stopwatchCode = CodeUtil.getCode(DataFactoryConstantPool.STOPWATCH_CODE_PREFIX,String.valueOf(stopwatchDO.getId()));
        stopwatchDO.setStopwatchCode(stopwatchCode);
        // 更新码表Code
        this.stopwatchManagementMapper.updateById(stopwatchDO);
        // 存入码表配置
        for (StopwatchConfigDTO stopwatchConfigDTO : createOrUpdateStopwatchDTO.getConfigList()) {
            //创建配置对象
            EncodingConfigurationDO encoding = new EncodingConfigurationDO();
            //为配置对象添加属性
            BeanUtils.copyProperties(stopwatchConfigDTO,encoding);
            encoding.setStopwatchName(stopwatchDO.getStopwatchName());
            encoding.setStopwatchCode(stopwatchDO.getStopwatchCode());
            //将配置存入数据库
            this.encodingConfigurationMapper.insert(encoding);
        }
        // 返回码表编号（新增接口参数配置进行码值定义时需要）
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS, stopwatchCode);
    }

    /**
     * @author 邹代鑫
     * @param createOrUpdateStopwatchDTO 新增、修改码表接收参数实体类
     * @return boolean
     * @description 编辑码表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> updateStopwatch(CreateOrUpdateStopwatchDTO createOrUpdateStopwatchDTO) {
        // 码表编号不能为空
        if (StringUtils.isBlank(createOrUpdateStopwatchDTO.getStopwatchCode())) {
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }

        // 判断修改的码表名称是否与数据库中其他数据重复
        LambdaQueryWrapper<StopwatchDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StopwatchDO::getStopwatchName, createOrUpdateStopwatchDTO.getStopwatchName())
                .ne(StopwatchDO::getStopwatchCode, createOrUpdateStopwatchDTO.getStopwatchCode());
        int count = stopwatchManagementMapper.selectCount(lambdaQueryWrapper);
        if (count > 0) {
            return R.Failed(ResultCodeEnum.STOPWATCH_NAME_EXIST);
        }

        //判断配置项名称是否相同
        List<StopwatchConfigDTO> configs = createOrUpdateStopwatchDTO.getConfigList();
        List<String> encodingValue = new ArrayList<>();
        List<String> encodingNames = new ArrayList<>();
        for (StopwatchConfigDTO config : configs) {
            encodingValue.add(config.getEncodingValue());
            encodingNames.add(config.getEncodingName());
        }
        // 判断新增码表配置项的码值取值是否存在重复
        boolean bool = SizeUtils.siblingRepetition(encodingValue);
        if (!bool){
            return R.Failed(ResultCodeEnum.ENCODING_CONFIGURATION_VALUE_REPEAT);
        }
        // 判断新增码表配置项的码值名称是否存在重复
        bool = SizeUtils.siblingRepetition(encodingNames);
        if (!bool){
            return R.Failed(ResultCodeEnum.ENCODING_CONFIGURATION_NAME_REPEAT);
        }

        //修改码表信息
        LambdaQueryWrapper<StopwatchDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StopwatchDO::getStopwatchCode, createOrUpdateStopwatchDTO.getStopwatchCode());
        StopwatchDO stopwatchDO = new StopwatchDO();
        BeanUtils.copyProperties(createOrUpdateStopwatchDTO,stopwatchDO);
        this.stopwatchManagementMapper.update(stopwatchDO,wrapper);

        //删除此码表全部的配置字段
        LambdaQueryWrapper<EncodingConfigurationDO> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(EncodingConfigurationDO::getStopwatchCode, createOrUpdateStopwatchDTO.getStopwatchCode());
        this.encodingConfigurationMapper.delete(deleteWrapper);

        //重新加载更新的配置字段
        if (createOrUpdateStopwatchDTO.getConfigList().size() < 1){
            throw new DataFactoryException(ResultCodeEnum.REQUEST_PARAM_NULL.getMessage());
        }
        //存入码表配置
        for (StopwatchConfigDTO stopwatchConfigDTO : createOrUpdateStopwatchDTO.getConfigList()) {
            //创建配置对象
            EncodingConfigurationDO encoding = new EncodingConfigurationDO();
            //为配置对象添加属性
            BeanUtils.copyProperties(stopwatchConfigDTO,encoding);
            encoding.setStopwatchName(stopwatchDO.getStopwatchName());
            encoding.setStopwatchCode(stopwatchDO.getStopwatchCode());
            //将配置存入数据库
            this.encodingConfigurationMapper.insert(encoding);
        }
        return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
    }

    /**
     * @author 章珑赢
     * @param parameterDTO 查询码表列表条件实体类
     * @return R
     * @description 查询码表列表
     */
    @Override
    public R<?> stopwatchList(StopwatchParameterDTO parameterDTO) {
        //分页类
        Page<StopwatchDO> page = new Page<>(parameterDTO.getPageNum(),parameterDTO.getPageSize());
        //条件构造器类
        LambdaQueryWrapper<StopwatchDO> wrapper = new LambdaQueryWrapper<>();
        //StringUtils.isNotBlank(pageCode.getStopwatchName())这句的意思是getStopwatchChName不为空就执行后面代码，为空就不再执行
        wrapper.like(StringUtils.isNotBlank(parameterDTO.getStopwatchName()), StopwatchDO::getStopwatchName, parameterDTO.getStopwatchName());
        wrapper.eq(StringUtils.isNotBlank(parameterDTO.getStopwatchStatus()), StopwatchDO::getStopwatchStatus, parameterDTO.getStopwatchStatus());
        wrapper.orderByDesc(StopwatchDO::getUpdateTime);
        wrapper.orderByAsc(StopwatchDO::getStopwatchStatus);
        Page<StopwatchDO> stopwatchPage = stopwatchManagementMapper.selectPage(page,wrapper);
        if(stopwatchPage == null){
            return R.Failed(ResultCodeEnum.OPERATION_FAILED);
        }
        return R.Success(ResultCodeEnum.SUCCESS, stopwatchPage);
    }

    /**
     * @author 章珑赢
     * @param stopwatchCode 码表编号
     * @return R
     * @description 删除码表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> deleteByStopwatch(String stopwatchCode) {
        // 删除码表配置
        QueryWrapper<EncodingConfigurationDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(DataFactoryConstantPool.STOPWATCH_CODE,stopwatchCode);
        this.encodingConfigurationMapper.delete(queryWrapper);
        LambdaQueryWrapper<StopwatchDO> wrapperStopwatchDo = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<EncodingConfigurationDO> configurationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        configurationLambdaQueryWrapper.eq(EncodingConfigurationDO::getStopwatchCode,stopwatchCode);
        wrapperStopwatchDo.eq(StopwatchDO::getStopwatchCode,stopwatchCode);
        wrapperStopwatchDo.eq(StopwatchDO::getStopwatchStatus, MyEnumClass.StatusEnum.NOT_RELEASE.getCode());
        if(this.stopwatchManagementMapper.delete(wrapperStopwatchDo) > 0){
            encodingConfigurationMapper.delete(configurationLambdaQueryWrapper);
            return R.Success(ResultCodeEnum.OPERATION_SUCCESS);
        }
       return R.Failed(ResultCodeEnum.OPERATION_FAILED);
    }

    /**
     * @author 李泓静
     * @param stopwatchCode 码表编号
     * @return R
     * @description 查看码表详情
     */
    @Override
    public R<?> getStopwatchDetail(String stopwatchCode) {
        LambdaQueryWrapper<EncodingConfigurationDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EncodingConfigurationDO::getStopwatchCode,stopwatchCode);
        List<EncodingConfigurationDO> encodingConfigurationList = encodingConfigurationMapper.selectList(wrapper);
        if(ObjectUtils.isEmpty(encodingConfigurationList)) {
            return R.Failed(ResultCodeEnum.REQUEST_OUT_OVERTIME);
        }
        List<StopwatchDetailVO> stopwatchDetailList = new ArrayList<>();
        for (EncodingConfigurationDO encodingConfiguration : encodingConfigurationList) {
            StopwatchDetailVO stopwatchDetail = new StopwatchDetailVO();
            BeanUtils.copyProperties(encodingConfiguration, stopwatchDetail);
            stopwatchDetailList.add(stopwatchDetail);
        }
        return R.Success(ResultCodeEnum.SUCCESS,stopwatchDetailList);
    }

    /**
     * @author 邹代鑫
     * @param response 请求响应参数
     * @return int
     * @description 导出标准码表
     */
    @Override
    public R<?> export(HttpServletResponse response) {
        try {
            //设置下载文件名
            String fileName = URLEncoder.encode("码表管理", "UTF-8");

            List<StopWatchExcelVO> stopWatchExcelVOList = new ArrayList<>();

            StopWatchExcelVO stopWatchExcel1 = new StopWatchExcelVO();
            stopWatchExcel1.setStopwatchName("性别");
            stopWatchExcel1.setStopwatchIllustrate("性别");
            //创建配置
            EncodingConfigurationExcelVO encodingConfigurationExcel1 = new EncodingConfigurationExcelVO();
            EncodingConfigurationExcelVO encodingConfigurationExcel2 = new EncodingConfigurationExcelVO();
            //添加配置属性
            encodingConfigurationExcel1.setEncodingValue("1");
            encodingConfigurationExcel1.setEncodingName("男性");
            encodingConfigurationExcel1.setEncodingMeaning("男性");

            encodingConfigurationExcel2.setEncodingValue("2");
            encodingConfigurationExcel2.setEncodingName("女性");
            encodingConfigurationExcel2.setEncodingMeaning("女性");
            //创建配置列表
            List<EncodingConfigurationExcelVO> excelList1 = new ArrayList<>();
            excelList1.add(encodingConfigurationExcel1);
            excelList1.add(encodingConfigurationExcel2);
            stopWatchExcel1.setList(excelList1);

            stopWatchExcelVOList.add(stopWatchExcel1);

            //导出表格
            ExcelUtils.exportExcel(stopWatchExcelVOList,null,"测试", StopWatchExcelVO.class,fileName,true,response);
            return R.Success(ResultCodeEnum.SUCCESS);
        } catch (IOException e) {
            e.printStackTrace();
            return R.Failed(ResultCodeEnum.EXCEL_EXPORT_FAILED);
        }
    }

    /**
     * @author 邹代鑫
     * @param file 文件
     * @return R
     * @description 导入表格
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> importExcel(MultipartFile file) {
        try {
            List<StopWatchExcelVO> data = ExcelUtils.importExcel(file, 0,2,StopWatchExcelVO.class);
            // 过滤掉不必要的数据集合
            for (int i = 0; i < data.size(); i++) {
                StopWatchExcelVO dataExcelVO = data.get(i);
                if (StringUtils.isBlank(dataExcelVO.getStopwatchName())){
                    data.remove(i);
                    i--;
                }
            }
            for (StopWatchExcelVO excelVO : data) {
                CreateOrUpdateStopwatchDTO stopwatchDTO = new CreateOrUpdateStopwatchDTO();
                //copy属性
                BeanUtils.copyProperties(excelVO,stopwatchDTO);
                //copy List
                List<StopwatchConfigDTO> list = BeanCopyUtil.copyListProperties(excelVO.getList(),StopwatchConfigDTO::new);
                stopwatchDTO.setConfigList(list);
                //调用新增进行添加
                this.addStopwatch(stopwatchDTO);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return R.Failed(ResultCodeEnum.EXCEL_IMPORT_FAILED);
        }
        return R.Success(ResultCodeEnum.SUCCESS);
    }


}
